<?php

/**
 * uniBoard Database Class
 *
 * Light and fast forum solution for web 2.0-like communities.
 *
 * @package		uniBoard
 * @author		Rafał Pitoń
 * @license		http://www.gnu.org/licenses/gpl-3.0.html
 * @since		Version 0.1
 * 
 * ------------------------------------------------------------------------
 * 
 * $Date: 2010-09-20 21:23:27 +0000 (Mon, 20 Sep 2010) $
 * $Revision: 64 $
 * $Author: rafio.xudb@gmail.com $
 */

// ------------------------------------------------------------------------

class class_db{
	
	/**
	 * Main class pointer
	 *
	 * @var object
	 */
	
	private $appCore		= NULL;
	
	/**
	 * Database connection pointer
	 *
	 * @var connection
	 */
	
	private $db_connection	= NULL;
	
	/**
	 * Query results stack
	 *
	 * @var array
	 */
	
	private $query_results	= array();
	
	/**
	 * Last result pointer
	 *
	 * @var resource
	 */
	
	private $last_result	= NULL;
	
	// ------------------------------------------------------------------------

	/**
	 * Creates DB connection or trows exception
	 *
	 * @param object $appCore
	 * @param string $db_host
	 * @param string $db_name
	 * @param string $db_user
	 * @param string $db_password
	 */
	
	function __construct( $appCore, $db_host, $db_name, $db_user, $db_password){
		
		// Store appCore pointer
		$this -> appCore = $appCore;
	
		// Determine if we are using MySQLi
		if ( DB_USE_MYSQLI)
		{	
			// Connect to DB host
			$this -> db_connection = mysqli_connect( $db_host, $db_user, $db_password);
			
			// Did we succeeded?
			if ( $this -> db_connection === false)
			{
				// Throw DB exception, it will be catched by CORE class
				throw new exc_critical( 'DB', 'Unable to establish connection with Database server.', mysqli_error());
			}
			
			// We are connected, first query will make connection use UTF-8
			mysqli_set_charset( 'utf8', $this -> db_connection);
			
			// Select base
			if ( !@mysqli_select_db( $db_name))
			{
				// Throw DB exception, it will be catched by CORE class
				throw new exc_critical( 'DB', 'Unable to select Database.', mysqli_error());
			}	
		}
		else
		{
			// Connect to DB host
			@$this -> db_connection = mysql_connect( $db_host, $db_user, $db_password);
			
			// Did we succeeded?
			if ( $this -> db_connection === false)
			{
				// Throw DB exception, it will be catched by CORE class
				throw new exc_critical( 'DB', 'Unable to establish connection with Database server.', mysql_error());
			}
			
			// We are connected, first query will make connection use UTF-8
			mysql_set_charset( 'utf8', $this -> db_connection);
			
			// Select base
			if ( @!mysql_select_db( $db_name))
			{
				// Throw DB exception, it will be catched by CORE class
				throw new exc_critical( 'DB', 'Unable to select Database.', mysql_error());
			}
			
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Destructor closses DB connection
	 *
	 */
	
	function __destruct(){
		
		// Close connection
		if ( DB_USE_MYSQLI)
		{
			// Use MySQLi method
			mysqli_close( $this -> db_connection);
		}
		else
		{
			// Use MySQL method
			mysql_close( $this -> db_connection);	
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Performs raw query
	 *
	 * @param string $sql
	 * @param bool $store_result
	 */
	
	function query( $sql, $store_result = true){
		
		// Try execute query
		try
		{
			// Store result?
			if ( $store_result)
			{
				// Return query result from proper function
				$this -> last_result = ( DB_USE_MYSQLI ? mysqli_query( $this -> db_connection, $sql) : mysql_query( $sql));
			
				// Add result to stack
				$this -> query_results[] = $this -> last_result;
			}
			else
			{
				// Simply perform query
				( DB_USE_MYSQLI ? mysqli_query( $this -> db_connection, $sql) : mysql_query( $sql));
			}
			
			// Crash software if we have error
			if ( strlen( DB_USE_MYSQLI ? mysqli_error( $this -> db_connection) : mysql_error()) > 0)
			{
				throw new exc_critical( 'DB', DB_USE_MYSQLI ? mysqli_error( $this -> db_connection) : mysql_error(), nl2br(htmlspecialchars( $sql)));
			}

			// Update statistics?
			if ( $this -> appCore -> conf['board_debug_level'] > 0)
			{
				$this -> appCore -> db_queries ++;
			}
			
			// List Query?
			if ( $this -> appCore -> conf['board_debug_level'] > 1)
			{
				$this -> appCore -> db_queries_l[] = $sql;
			}
		}
		catch ( exc_critical $exception)
		{
			// Kill script runtime
			exit( $exception);
		}

	}
	
	// ------------------------------------------------------------------------

	/**
	 * Fetches array and returns row
	 *
	 * @return array
	 */
	
	function fetch_array(){
		
		// Fetch array using correct function
		return ( DB_USE_MYSQLI ? mysqli_fetch_array( $this -> last_result, MYSQLI_NUM) : mysql_fetch_array( $this -> last_result, MYSQL_NUM));
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Fetches array and returns row as assoc array
	 *
	 * @return array
	 */
	
	function fetch_assoc(){
		
		// Fetch array using correct function
		return ( DB_USE_MYSQLI ? mysqli_fetch_assoc( $this -> last_result) : mysql_fetch_assoc( $this -> last_result));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Performs insert operation
	 *
	 * @param array $data
	 * @param string $table
	 */
	
	function insert( $data, $table){

		// Empty columns container
		$columns = '';
		
		// Empty values container
		$values = '';
		
		// Reiterate data
		foreach ( $data as $column => $value)
		{
			// Add column to columns
			$columns .= ', ' . $column;
			
			// Add field to value
			$values .= ', \'' . $value . '\'';			
		}
		
		// Perform query
		$this -> query( 'INSERT INTO ' . DB_PREFIX . $table . ' (' . substr( $columns, 2) . ') VALUES (' . substr( $values, 2) . ')', false);
				
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Performs multiple insert operation
	 *
	 * @param string $columns
	 * @param array $data
	 * @param string $table
	 */
	
	function multipleInsert( $columns, $data, $table){

		// Perform query
		$this -> query( 'INSERT INTO ' . DB_PREFIX . $table . ' (' . $columns . ') VALUES (' . join( '), (', $data) . ')', false);
				
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Performs update operation
	 *
	 * @param array $data
	 * @param string $table
	 * @param string $condition
	 */
	
	function update( $data, $table, $condition = ''){
		
		// Empty values container
		$values = '';
			
		// Reiterate data
		foreach ( $data as $column => $value)
		{			
			// Add field to value
			if ( is_array( $value) && $value[1])
			{
				// Value without quotes
				$values .= ', ' . $column . ' = ' . $value;
			}
			else
			{
				// Value in quotes
				$values .= ', ' . $column . ' = \'' . $value . '\'';
			}			
		}
		
		// Perform query
		$this -> query( 'UPDATE ' . DB_PREFIX . $table . ' SET ' . substr( $values, 2) . ( empty( $condition) ? '' : ' WHERE ' . $condition), false);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Performs delete operation
	 *
	 * @param string $table
	 * @param string $condition
	 */
	
	function delete( $table, $condition = ''){
				
		// Build and execute query
		$this -> query( 'DELETE FROM ' . DB_PREFIX . $table . ( empty( $condition) ? '' : ' WHERE ' . $condition), false);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Performs count query
	 *
	 * @param string $table
	 * @param string $condition
	 */
	
	function count( $table, $condition = ''){
				
		// Build and execute query
		$this -> query( 'SELECT COUNT(*) FROM ' . DB_PREFIX . $table . ( empty( $condition) ? '' : ' WHERE ' . $condition));
		
		// Result
		$result = $this -> fetch_array();
		
		// Free result
		$this -> freeResult();
		
		// Return count result
		return $result[0];
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Returns id from last insert operation
	 *
	 * @return string
	 */
	
	function insertId(){

		// Return correct number of rows using right engine method
		return ( DB_USE_MYSQLI ? mysqli_insert_id( $this -> db_connection) : mysql_insert_id( $this -> db_connection));
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Returns number of rows affected in last operation
	 *
	 * @return integer
	 */
	
	function numRows(){

		// Return correct number of rows using right engine method
		return ( DB_USE_MYSQLI ? mysqli_num_rows( $this -> last_result) : mysql_num_rows( $this -> last_result));
		
	}
		
	// ------------------------------------------------------------------------

	/**
	 * Resets result internal pointer
	 *
	 */
	
	function resetResult(){

		// Free result
		if ( DB_USE_MYSQLI)
		{
			mysqli_data_seek( $this -> last_result, 0);
		}
		else
		{
			mysql_data_seek( $this -> last_result, 0);
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Frees result and memory
	 *
	 */
	
	function freeResult(){

		// Free result
		if ( DB_USE_MYSQLI)
		{
			mysqli_free_result( $this -> last_result);
		}
		else
		{
			mysql_free_result( $this -> last_result);
		}
		
		// Kill last item of stack
		array_pop( $this -> query_results);
		
		// Update last result
		$this -> last_result = end( $this -> query_results);
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Secures string for our query by escapes
	 *
	 * @param string $string
	 * @param bool $in_like
	 * @return string
	 */
	
	function strEscape( $string, $in_like = false){
			 
		// Escape like
		if ( $in_like)
		{
			// Backslash wildcars
			$string = str_replace( '%', '\%', $string);	
			$string = str_replace( '_', '\_', $string);	
		}
		
		// Return escaped string
		return ( DB_USE_MYSQLI ? mysqli_escape_string( $this -> db_connection, $string) : mysql_real_escape_string( $string, $this -> db_connection));
		
	}
	
}